Factory Pattern

2 min read
Foundational2 min read
Rapid overview

Factory Pattern

TL;DR

Centralize creation of objects (like API handlers or executors) based on configuration or environment.

How it works


🧩 Example — Trading platform executor factory

public interface ITradeExecutor
{
    void Execute(Order order);
}

public class Mt4Executor : ITradeExecutor
{
    public void Execute(Order order) =>
        Console.WriteLine($"[MT4] Executing {order.Symbol}");
}

public class Mt5Executor : ITradeExecutor
{
    public void Execute(Order order) =>
        Console.WriteLine($"[MT5] Executing {order.Symbol}");
}

public static class ExecutorFactory
{
    public static ITradeExecutor Create(string platform) => platform switch
    {
        "MT4" => new Mt4Executor(),
        "MT5" => new Mt5Executor(),
        _ => throw new ArgumentException("Unknown platform")
    };
}

// --- Usage ---
var platform = "MT5";
var executor = ExecutorFactory.Create(platform);
executor.Execute(new Order { Symbol = "USDJPY", Amount = 5000 });

✅ Why it matters:

  • Simplifies platform switching (MT4, MT5, FIX, cTrader).
  • New platforms require no refactor — just a new class and switch entry.

Quick recall Q&A

Q: When should you use a Factory pattern in .NET services?

When object creation depends on runtime context (config, tenant, instrument) and you want to isolate creation logic from consumers. Factories prevent scattered new calls and keep construction consistent.

Q: How does DI interact with factories?

You can register implementations in DI and inject Func<Key, ITradeExecutor> or an IExecutorFactory that resolves services by key. This keeps factories composable with scoped dependencies.

Q: How do you avoid giant switch statements as platforms grow?

Use a dictionary of delegates, reflection-based registration, or DI IServiceProvider lookups keyed by platform. Alternatively, combine with the Strategy pattern so each executor registers itself.

Q: What’s the benefit of abstract factories?

When you need to create families of related objects (e.g., executor + validator + serializer per platform), an abstract factory ensures compatible components are produced together.

Q: How do factories aid testing?

Tests can inject fake factories returning mock executors, isolating code under test without hitting real integrations. It also simplifies verifying that the correct executor is chosen for a scenario.

Q: How do you handle configuration-driven factories?

Load mappings from configuration or feature flags, then let the factory instantiate types via DI. This enables runtime toggles (e.g., route VIP tenants to a premium executor) without code changes.

Q: When is the factory pattern overkill?

When only two concrete types exist and creation logic is trivial. Start simple, and introduce a factory once switching logic repeats or needs shared validation/logging.

Q: How do you ensure factories remain SRP-compliant?

Keep them focused on creation. Any orchestration, validation, or logging should be delegated to other components or decorators so factories don't become god objects.

Q: Can factories return async results?

Yes—define methods returning Task<T> if creation involves I/O (e.g., pulling secrets). Just ensure callers understand the lifecycle and avoid blocking .Result.

Q: How do you register factories in DI?

Register each concrete type and a factory delegate: services.AddTransient<ExecutorFactory>(); or services.AddSingleton<Func<string, ITradeExecutor>>(provider => key => provider.GetRequiredKeyedService<ITradeExecutor>(key));.

See also